#pragma once

#include <iostream>
#include <poll.h>
#include <string>
#include <cstdio>
#include <unistd.h>
#include "Socket.hpp"
#include "Log.hpp"

static const uint16_t defaultport = 28080;
static const int fd_num_max = 64;
int defaultfd = -1;
int non_event = 0;

class PollServer{
public:
    PollServer(const uint16_t &port = defaultport)
    : _port(port)
    {
        for (int i = 0; i < fd_num_max; i++){
            _event_fds[i].fd = defaultfd;
            _event_fds[i].events = non_event;
            _event_fds[i].revents = non_event;
        }
    }

private:
    void Accepter(){
        std::string clientip;
        uint16_t clientport = 0;
        int newfd=_listensock.Accept(&clientip, &clientport);
        if (newfd < 0){
            log(Error, "link accept error...");
            return;
        }
        log(INFO, "link accept success, fd is %d", newfd);
        int pos = 1;
        for (; pos < fd_num_max; pos++){
            if (_event_fds[pos].fd == defaultfd){
                break;
            }
        }

        if (pos == fd_num_max){
            log(Warning, "Server full, close %d now", newfd);
            close(newfd);
            // 或者扩容
            return;
        }
        else{
            _event_fds[pos].fd = newfd;
            _event_fds[pos].events = POLLIN;
            _event_fds[pos].revents = non_event;
        }
    }

    void Reader(const int &fd, const int &pos){
        char buffer[1024];
        ssize_t n = read(fd, buffer, sizeof(buffer)-1);
        if(n < 0){
            log(Error, "read error, close %d now", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd;
            _event_fds[pos].events = non_event;
            _event_fds[pos].revents = non_event;
        }
        else if (n == 0){
            log(INFO, "client quit, me too, close %d now", fd);
            close(fd);
            _event_fds[pos].fd = defaultfd;
            _event_fds[pos].events = non_event;
            _event_fds[pos].revents = non_event;
        }
        else{
            buffer[n] = 0;
            log(INFO, "get a message: %s, fd is %d", buffer, fd);
        }
    }

    void EventEventDispatcher(){
        for (int i = 0; i < fd_num_max; i++){
            int fd = _event_fds[i].fd;
            if (fd != defaultfd){
                if(_event_fds[i].revents & POLLIN){
                    if(fd==_listensock.Fd()){
                        log(INFO, "Get a new link...");
                        Accepter();
                    }
                    else{
                        log(INFO, "Have data read...");
                        Reader(fd, i);
                    }
                }
            }
        }
    }

public:

    bool Init(){
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();

        return true;
    }

    void Start(){
        _event_fds[0].fd = _listensock.Fd();
        _event_fds[0].events = POLLIN;
        int timeout = 3000;
        while(true){
            int n = poll(_event_fds, fd_num_max, timeout);
            switch(n){
                case 0:
                    log(INFO, "Poll time out...");
                    break;
                case -1:
                    log(Error, "Poll error...");
                    break;
                default:
                    log(INFO, "There is an event triggered...");
                    EventEventDispatcher();
                    break;
            }
        }
    }

    ~PollServer(){
        _listensock.Close();
    }

private:
    MySocket _listensock;
    uint16_t _port;
    struct pollfd _event_fds[fd_num_max];
};
